package edu.uoc.tdp.servidor.bbdd.conexio;

import edu.uoc.tdp.bbdd.GestorDiscConnexio;
import edu.uoc.tdp.beans.conexio.Administrador;
import edu.uoc.tdp.beans.conexio.Estudiant;
import edu.uoc.tdp.beans.conexio.ResponsableEvents;
import edu.uoc.tdp.beans.conexio.Usuari;
import edu.uoc.tdp.common.EOlympicsException;
import edu.uoc.tdp.common.EOlympicsExceptionConnexio;
import edu.uoc.tdp.common.EOlympicsUtils;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * Classe GestorUsuaris
 * TDP Grup TDP 1X4J
 */
public class GestorUsuaris {
    
    private GestorDiscConnexio gestor;
    private Connection connexio;

    /**
     * Constructor de la classe Gestora
     * Crea un nou gestor de disc.
     */
    public GestorUsuaris() throws EOlympicsExceptionConnexio {
        this.gestor = new GestorDiscConnexio();
        this.gestor.obreConnexioBD();
        this.connexio = gestor.getConnexio();
    }

    /**
     * Constructor de la classe Gestora
     * Utilitza el gestor de disc passat com a paràmetre
     * @param gdc connexió a la BD de tipus GestorDiscConnexio
     */
    public GestorUsuaris(GestorDiscConnexio gdc) {
        this.gestor   = gdc;
        this.connexio = gdc.getConnexio();
    }
    
    
    /**
     * Consulta d'un Usuari pel seu Id Intern
     * @param IdUsu Identificador de l'Usuari
     * @return objecte Usuari amb Identificador igual al passat com a paràmete
     * @exception EOlympicsExceptionConnexio
     */
    public Usuari obtenirUsuari(int IdUsu) throws EOlympicsExceptionConnexio {
        Usuari usu = null;
        Statement sentencia = gestor.creaSentencia();
        String select = "SELECT idUsuari, pwd, email, " +
                "tipusDocumentId, document, nom, cognom1, " +
                "cognom2, estatEnSistema, dataAlta, dataBaixa, dataMod " +
                "FROM USUARI " + 
                "WHERE idIntern = " + IdUsu;
        try {
            ResultSet rs = sentencia.executeQuery(select);
            if (rs.next()) {
                usu = new Usuari(IdUsu, rs.getString(1), rs.getString(2),
                                 rs.getString(3), rs.getString(4),
                                 rs.getString(5), rs.getString(6),
                                 rs.getString(7), rs.getString(8),
                                 rs.getString(9));
                usu.setDataCreacio(rs.getDate(10));
                usu.setDataEsborrat(rs.getDate(11));
                usu.setDataModificacio(rs.getDate(12));
}
            rs.close();
            sentencia.close();

        } catch (SQLException sqle) {
            System.out.println(sqle.getMessage());
            throw new EOlympicsExceptionConnexio(EOlympicsException.ERR_SQL);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            throw new EOlympicsExceptionConnexio(EOlympicsException.ERR_DESC_EXEC);
        }
        return usu;
    }

    /**
     * Consulta d'un Administrador pel seu Id Intern
     * @param IdUsu Identificador de l'Administrador
     * @return objecte Administrador amb Identificador igual al passat com a paràmete
     * @exception EOlympicsExceptionConnexio
     */
    public Administrador obtenirAdministrador(int IdAdm) throws EOlympicsExceptionConnexio {
        Administrador adm = null;
        Statement sentencia = gestor.creaSentencia();
        String select = "SELECT u.idUsuari, u.pwd, u.email, " +
                "u.tipusDocumentId, u.document, u.nom, u.cognom1, u.cognom2, u.estatEnSistema " +
                "FROM ADMINISTRADOR as a, USUARI as u " + 
                "WHERE a.idAdministrador = " + IdAdm +
                " AND a.idAdministrador = u.idIntern" +
                " AND u.tipusUsuari = 'A'";
        try {
            ResultSet rs = sentencia.executeQuery(select);
            if (rs.next()) {
                adm = new Administrador(IdAdm, rs.getString(1), rs.getString(2),
                                 rs.getString(3), rs.getString(4),
                                 rs.getString(5), rs.getString(6),
                                 rs.getString(7), rs.getString(8),
                                 rs.getString(9));
            }
            rs.close();
            sentencia.close();

        } catch (SQLException sqle) {
            System.out.println(sqle.getMessage());
            throw new EOlympicsExceptionConnexio(EOlympicsException.ERR_SQL);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            throw new EOlympicsExceptionConnexio(EOlympicsException.ERR_DESC_EXEC);
        }
        return adm;
    }
    
    /**
     * Consulta d'un Responsable d'events pel seu Id Intern
     * @param IdREv Identificador del responsable d'events
     * @return objecte ResponsableEvents amb Identificador igual al passat com a paràmete
     * @exception EOlympicsExceptionConnexio
     */
    public ResponsableEvents obtenirResponsableEvents(int IdREv) throws EOlympicsExceptionConnexio {
        ResponsableEvents REv = null;
        Statement sentencia = gestor.creaSentencia();
        String select = "SELECT u.idUsuari, u.pwd, u.email, " +
                "u.tipusDocumentId, u.document, u.nom, u.cognom1, u.cognom2, u.estatEnSistema " +
                "FROM RESPONSABLEEVENTS as r, USUARI as u " + 
                "WHERE r.idResponsable = " + IdREv + " " +
                "AND r.idResponsable = u.idIntern" +
                " AND u.tipusUsuari = 'R'";
        try {
            ResultSet rs = sentencia.executeQuery(select);
            if (rs.next()) {
                REv = new ResponsableEvents(IdREv, rs.getString(1), rs.getString(2),
                                 rs.getString(3), rs.getString(4),
                                 rs.getString(5), rs.getString(6),
                                 rs.getString(7), rs.getString(8),
                                 rs.getString(9));
            }
            rs.close();
            sentencia.close();

        } catch (SQLException sqle) {
            System.out.println(sqle.getMessage());
            throw new EOlympicsExceptionConnexio(EOlympicsException.ERR_SQL);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            throw new EOlympicsExceptionConnexio(EOlympicsException.ERR_DESC_EXEC);
        }
        return REv;
    }
    
    /**
     * Consulta d'un estudiant pel seu Id Intern
     * @param IdEst Identificador de l'estudiant
     * @return objecte Estudiant amb Identificador igual al passat com a paràmete
     * @exception EOlympicsExceptionConnexio
     */
    public Estudiant obtenirEstudiant(int IdEst) throws EOlympicsExceptionConnexio {
        Estudiant est = null;
        Statement sentencia = gestor.creaSentencia();
        String select = "SELECT e.universitat, u.idUsuari, u.pwd, u.email, " +
                "u.tipusDocumentId, u.document, u.nom, u.cognom1, u.cognom2, u.estatEnSistema " +
                "FROM ESTUDIANT as e, USUARI as u " + 
                "WHERE e.idEstudiant = " + IdEst +
                " AND e.idEstudiant = u.idIntern" +
                " AND u.tipusUsuari = 'E'";
        try {
            ResultSet rs = sentencia.executeQuery(select);
            if (rs.next()) {
                est = new Estudiant(IdEst, rs.getString(1), rs.getString(2),
                                    rs.getString(3), rs.getString(4),
                                    rs.getString(5), rs.getString(6),
                                    rs.getString(7), rs.getString(8),
                                    rs.getString(9), rs.getString(10));
            }
            rs.close();
            sentencia.close();

        } catch (SQLException sqle) {
            System.out.println(sqle.getMessage());
            throw new EOlympicsExceptionConnexio(EOlympicsException.ERR_SQL);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            throw new EOlympicsExceptionConnexio(EOlympicsException.ERR_DESC_EXEC);
        }
        return est;
    }

    /**
     * Mètode que obté la llista d'usuaris del sistema donats o no de baixa
     *
     * @param nom Text de filtre pel nom d'usuari
     * @param cognoms Text de filtre pels cognoms de l'usuari
     * @param ident Text de filtre per l'identificador d'usuari
     * @return Llista dels Usuaris
     * @exception EOlympicsExceptionConnexio
     */
    public List<Usuari> obtenirLlistaUsuaris(String nom, String cognoms, String ident) throws EOlympicsExceptionConnexio {
        List<Usuari> LlistaUsuaris = new ArrayList<Usuari>();
        Usuari Usuari;

        try {
            Statement sentencia = gestor.creaSentencia();
            String select = "SELECT idIntern, idUsuari, pwd, email, " +
                            "tipusDocumentId, document, nom, cognom1, cognom2, "+
                            "estatEnSistema, dataAlta, dataBaixa, dataMod" +
                            " FROM USUARI";
            if (!nom.isEmpty()) {
                select = select + " WHERE nom LIKE '%" + nom + "%'";
            }
            if (!cognoms.isEmpty()) {
                String [ ] cogn = cognoms.split("\\ ");
                if (cogn.length >= 1) {
                  if (!nom.isEmpty()) {
                      select = select + " AND";
                  } else {
                      select = select + " WHERE";
                  }
                  select = select + " cognom1 LIKE '%" + cogn[0] + "%'";
                } 
                if (cogn.length >= 2) {
                  select = select + " AND cognom2 LIKE '%" + cogn[1] + "%'";
                }
            }
            if (!ident.isEmpty()) {
                if (!nom.isEmpty() | !cognoms.isEmpty()) {
                      select = select + " AND";
                  } else {
                      select = select + " WHERE";
                  }
                select = select + " idUsuari LIKE '%" + ident + "%'";
            }
            select = select + " ORDER BY cognom1, cognom2, nom";
            ResultSet rs = sentencia.executeQuery(select);
            while (rs.next()) {
                Usuari = new Usuari(rs.getInt(1), rs.getString(2),
                                    rs.getString(3), rs.getString(4),
                                    rs.getString(5), rs.getString(6),
                                    rs.getString(7), rs.getString(8),
                                    rs.getString(9), rs.getString(10));
                Usuari.setDataCreacio(rs.getDate(11));
                Usuari.setDataEsborrat(rs.getDate(12));
                Usuari.setDataModificacio(rs.getDate(13));
                LlistaUsuaris.add(Usuari);
            }
            rs.close();
            sentencia.close();
        } catch (SQLException sqle) {
            System.out.println(sqle.getMessage());
            throw new EOlympicsExceptionConnexio(EOlympicsExceptionConnexio.ERR_SQL_LLISUSU);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            throw new EOlympicsExceptionConnexio(EOlympicsExceptionConnexio.ERR_DESC_EXEC_LLISUSU);
        }
        return LlistaUsuaris;
    }    
    
    
    /**
     * Insereix a la BD un Usuari
     * @param usu Usuari de l'aplicatiu
     * @param tipus Tipus Usuari de l'aplicatiu
     * @param idAdmin Identificador intern de l'administrador que fa l'alta
     * @return true si la inserció s'ha fet
     * @exception EOlympicsExceptionConnexio
     */
    public boolean inserirUsuari(Usuari usu, String tipus, int idAdmin) throws EOlympicsExceptionConnexio {
        boolean ok = false;
        try {
            String insert = "INSERT INTO USUARI (tipusUsuari, idUsuari, pwd, "+
                            "email, estatEnSistema, tipusDocumentId, document, "+
                            "nom, cognom1, cognom2, dataAlta, usuariAlta, dataBaixa, "+
                            "usuariBaixa, dataMod, usuariMod) "+
                            "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, null, null, null, null)";
            
            PreparedStatement pstu = gestor.crearPreparedStatement(insert);
            pstu.setString(1, tipus);
            pstu.setString(2, usu.getIdUsuari());
            pstu.setString(3, usu.getPwd());
            pstu.setString(4, usu.getEmail());
            pstu.setString(5, usu.getEstatEnSistema());
            pstu.setString(6, usu.getTipusDocumentId());
            pstu.setString(7, usu.getDocument());
            pstu.setString(8, usu.getNom());
            pstu.setString(9, usu.getCognom1());
            pstu.setString(10, usu.getCognom2());
            // Agafar data actual i transformar-la per a poder insertar-la a la BD
            Date avui = new Date(System.currentTimeMillis());
            pstu.setDate(11, avui);
            pstu.setInt(12, idAdmin);
            pstu.execute();
            pstu.close();
            
            ok = true;
            
        } catch (SQLException sqle) {
            System.out.println(sqle.getMessage());
            throw new EOlympicsExceptionConnexio(EOlympicsExceptionConnexio.ERR_SQL_ALTAUSU);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            throw new EOlympicsExceptionConnexio(EOlympicsExceptionConnexio.ERR_DESC_EXEC_ALTAUSU);
        }

        return ok;
    }
    
    /**
     * Insereix a la BD un Administrador
     * @param usu Usuari de l'aplicatiu
     * @param idAdmin Identificador intern de l'administrador que fa l'alta
     * @return true si la inserció s'ha fet
     * @exception EOlympicsExceptionConnexio
     */
    public boolean inserirAdministrador(Usuari usu, int idAdmin) throws EOlympicsExceptionConnexio {
        boolean ok = false;
        try {
            if (inserirUsuari(usu, "A", idAdmin)) {
                String insert = "INSERT INTO ADMINISTRADOR (idAdministrador) "
                        + "SELECT idIntern FROM USUARI "
                        + "WHERE tipusUsuari = 'A' AND idUsuari = ? AND pwd = ?";
                PreparedStatement psta = gestor.crearPreparedStatement(insert);
                psta.setString(1, usu.getIdUsuari());
                psta.setString(2, usu.getPwd());
                psta.execute();
                psta.close();

                ok = true;
            }

        } catch (SQLException sqle) {
            System.out.println(sqle.getMessage());
            throw new EOlympicsExceptionConnexio(EOlympicsExceptionConnexio.ERR_SQL_ALTAADM);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            throw new EOlympicsExceptionConnexio(EOlympicsExceptionConnexio.ERR_DESC_EXEC_ALTAADM);
        }

        return ok;
    }
    
    /**
     * Insereix a la BD un Responsable d'Events
     * @param usu Usuari de l'aplicatiu
     * @param idAdmin Identificador intern de l'administrador que fa l'alta
     * @return true si la inserció s'ha fet
     * @exception EOlympicsExceptionConnexio
     */
    public boolean inserirResponsableEvents(Usuari usu, int idAdmin) throws EOlympicsExceptionConnexio {
        boolean ok = false;
        try {
            if (inserirUsuari(usu, "R", idAdmin)) {
                String insert = "INSERT INTO RESPONSABLEEVENTS (idResponsable) "
                        + "SELECT idIntern FROM USUARI "
                        + "WHERE tipusUsuari = 'R' AND idUsuari = ? AND pwd = ?";
                PreparedStatement pstr = gestor.crearPreparedStatement(insert);
                pstr.setString(1, usu.getIdUsuari());
                pstr.setString(2, usu.getPwd());
                pstr.execute();
                pstr.close();

                ok = true;
            }

        } catch (SQLException sqle) {
            System.out.println(sqle.getMessage());
            throw new EOlympicsExceptionConnexio(EOlympicsExceptionConnexio.ERR_SQL_ALTAREE);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            throw new EOlympicsExceptionConnexio(EOlympicsExceptionConnexio.ERR_DESC_EXEC_ALTAREE);
        }

        return ok;
    }
    
    /**
     * Insereix a la BD un Estudiant
     * @param usu Usuari de l'aplicatiu
     * @param nomUniversitat Nom de la universitat a la que pertany
     * @param idAdmin Identificador intern de l'administrador que fa l'alta
     * @return true si la inserció s'ha fet
     * @exception EOlympicsExceptionConnexio
     */
    public boolean inserirEstudiant(Usuari usu, String nomUniversitat, int idAdmin) throws EOlympicsExceptionConnexio {
        boolean ok = false;
        try {
            if (inserirUsuari(usu, "E", idAdmin)) {

                String insert = "INSERT INTO ESTUDIANT (idEstudiant, universitat) "
                        + "SELECT idIntern, ? FROM USUARI "
                        + "WHERE tipusUsuari = 'E' AND idUsuari = ? AND pwd = ?";
                PreparedStatement pste = gestor.crearPreparedStatement(insert);
                pste.setString(1, nomUniversitat);
                pste.setString(2, usu.getIdUsuari());
                pste.setString(3, usu.getPwd());
                pste.execute();
                pste.close();

                ok = true;
            }

        } catch (SQLException sqle) {
            System.out.println(sqle.getMessage());
            throw new EOlympicsExceptionConnexio(EOlympicsExceptionConnexio.ERR_SQL_ALTAEST);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            throw new EOlympicsExceptionConnexio(EOlympicsExceptionConnexio.ERR_DESC_EXEC_ALTAEST);
        }

        return ok;
    }
    
    
    /**
     * Actualitza dades modificades de l'usuari
     * @param usu Usuari de l'aplicatiu
     * @param idAdmin Identificador intern de l'administrador que fa la modificació
     * @return true si l'actualització dels camps de l'ususari s'ha fet
     * @exception EOlympicsExceptionConnexio
     */
    public boolean actualitzaUsuari(Usuari usu, int idAdmin) throws EOlympicsExceptionConnexio {
        boolean ok = false;
            
        String stUpd = "UPDATE USUARI SET idUsuari = ?, pwd = ?, email = ?, " +
                       " estatEnSistema = ?, tipusDocumentId = ?, " +
                       " document = ?, nom = ?, cognom1 = ?, cognom2 = ?, " +
                       " dataMod = ?, usuariMod = ?" +
                       " WHERE idIntern = ?";
        
        try {
            PreparedStatement pstu = gestor.crearPreparedStatement(stUpd);
            pstu.setString(1, usu.getIdUsuari());
            pstu.setString(2, usu.getPwd());
            pstu.setString(3, usu.getEmail());
            pstu.setString(4, usu.getEstatEnSistema());
            pstu.setString(5, usu.getTipusDocumentId());
            pstu.setString(6, usu.getDocument());
            pstu.setString(7, usu.getNom());
            pstu.setString(8, usu.getCognom1());
            pstu.setString(9, usu.getCognom2());
            // Agafar data actual i transformar-la per a poder posar-la a la BD
            Date avui = new Date(System.currentTimeMillis());
            pstu.setDate(10, avui);
            pstu.setInt(11, idAdmin);
            pstu.setInt(12, usu.getIdIntern());
            pstu.execute();
            ok = true;
            pstu.close();

        } catch (SQLException sqle) {
            System.out.println(sqle.getMessage());
            throw new EOlympicsExceptionConnexio(EOlympicsExceptionConnexio.ERR_SQL_MODUSU);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            throw new EOlympicsExceptionConnexio(EOlympicsExceptionConnexio.ERR_DESC_EXEC_MODUSU);
        }
        return ok;
    }
    
    /**
     * Actualitza dades modificades de l'estudiant
     * @param usu Usuari de l'aplicatiu
     * @param nomUniversitat Nom de la universitat a la que pertany
     * @param idAdmin Identificador intern de l'administrador que fa la modificació
     * @return true si l'actualització dels camps de l'ususari s'ha fet
     * @exception EOlympicsExceptionConnexio
     */
    public boolean actualitzaEstudiant(Usuari usu, String nomUniversitat, int idAdmin) throws EOlympicsExceptionConnexio {
        boolean ok = false;
        String stUpd = "UPDATE ESTUDIANT SET universitat = ?" +
                       " WHERE idEstudiant = ?";

        try {
            PreparedStatement pste = gestor.crearPreparedStatement(stUpd);
            pste.setString(1, nomUniversitat);
            pste.setInt(2, usu.getIdIntern());
            pste.execute();
            pste.close();
            ok = actualitzaUsuari(usu, idAdmin);

        } catch (SQLException sqle) {
            System.out.println(sqle.getMessage());
            throw new EOlympicsExceptionConnexio(EOlympicsExceptionConnexio.ERR_SQL_MODEST);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            throw new EOlympicsExceptionConnexio(EOlympicsExceptionConnexio.ERR_DESC_EXEC_MODEST);
        }
        return ok;
    }
    
    /**
     * Actualitza dades de l'usuari marcant-lo com a borrat
     * @param usu Usuari de l'aplicatiu
     * @param idAdmin Identificador intern de l'administrador que fa el borrat
     * @return true si l'actualització dels camps de l'usuari s'ha fet
     * @exception EOlympicsExceptionConnexio
     */
    public boolean esborraUsuari(int idInternUsuari, int idAdmin) throws EOlympicsExceptionConnexio {
        boolean ok = false;
        Date avui = new Date(System.currentTimeMillis());
            
        String stUpd = "UPDATE USUARI SET" + 
                       " dataBaixa = '" + EOlympicsUtils.getStringDateSimpleFormat(avui) + "', " +
                       " usuariBaixa = " + idAdmin +
                       " WHERE idIntern = " + idInternUsuari;
        
        try {
            Statement sentencia = gestor.creaSentencia();
            sentencia.executeUpdate(stUpd);
            ok = true;
            sentencia.close();

        } catch (SQLException sqle) {
            System.out.println(sqle.getMessage());
            throw new EOlympicsExceptionConnexio(EOlympicsExceptionConnexio.ERR_SQL_BORRUSU);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            throw new EOlympicsExceptionConnexio(EOlympicsExceptionConnexio.ERR_DESC_EXEC_BORRUSU);
        }
        return ok;
    }
    
    /**
     * Revisa si un document identificatiu el té un altre usuari diferent del testejat
     * @param document Document a comprovar
     * @param IdUsu Identificador de l'usuari que no s'ha de tenir en compte en el test
     * @return true si s'ha trobat un altre usuari amb aquest document.
     * @exception EOlympicsExceptionConnexio
     */
    public boolean documentRepetit(String document, int IdUsu) throws EOlympicsExceptionConnexio {
        boolean ok = false;
        Statement sentencia = gestor.creaSentencia();
        String select = "SELECT document FROM USUARI "
                      + "WHERE idIntern <> " + IdUsu
                      + " AND document = '" + document + "'";
        try {
            ResultSet rs = sentencia.executeQuery(select);
            if (rs.next()) {
                ok = true;
            }
            rs.close();
            sentencia.close();

        } catch (SQLException sqle) {
            System.out.println(sqle.getMessage());
            throw new EOlympicsExceptionConnexio(EOlympicsException.ERR_SQL);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            throw new EOlympicsExceptionConnexio(EOlympicsException.ERR_DESC_EXEC);
        }
        return ok;
    }

    /**
     * Revisa si un identificador usuari el té un altre diferent del testejat
     * @param idUsuari Identificador usuari a comprovar
     * @param IdIntUsu Identificador de l'usuari que no s'ha de tenir en compte en el test
     * @return true si s'ha trobat un altre usuari amb aquest identificador.
     * @exception EOlympicsExceptionConnexio
     */
    public boolean identificadorRepetit(String idUsuari, int IdIntUsu) throws EOlympicsExceptionConnexio {
        boolean ok = false;
        Statement sentencia = gestor.creaSentencia();
        String select = "SELECT document FROM USUARI "
                      + "WHERE idIntern <> " + IdIntUsu
                      + " AND idUsuari = '" + idUsuari+ "'";
        try {
            ResultSet rs = sentencia.executeQuery(select);
            if (rs.next()) {
                ok = true;
            }
            rs.close();
            sentencia.close();

        } catch (SQLException sqle) {
            System.out.println(sqle.getMessage());
            throw new EOlympicsExceptionConnexio(EOlympicsException.ERR_SQL);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            throw new EOlympicsExceptionConnexio(EOlympicsException.ERR_DESC_EXEC);
        }
        return ok;
    }

}
